package proxy.dynamic;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyDemo {

    public static void main(String[] args) {
        // -Dcglib.debugLocation=com\cglib\proxy
        System.getProperties().put("cglib.debugLocation", "com\\cglib\\proxy");
        BusinessService businessService = new BusinessServiceImpl();
        Enhancer enhancer = new Enhancer();
        // 为代理类指定需要代理的类，也即是父类
        enhancer.setSuperclass(BusinessServiceImpl.class);
        MethodInterceptor cglibMethodInterceptor = new LogAroundMethodInterceptor(businessService);
        // 设置方法拦截器回调引用，对于代理类上所有方法的调用，都会调用CallBack，而Callback则需要实现intercept() 方法进行拦截
        enhancer.setCallback(cglibMethodInterceptor);
        BusinessService businessServiceProxy = (BusinessService) enhancer.create();
        // 增强生效
        businessServiceProxy.interfaceMethod2();

        // interfaceMethod1方法内部调用了interfaceMethod2方法，interfaceMethod2方法的增强不生效
        // 因为增强是没有改变委托类，内部还是调用【目标对象】的interfaceMethod2
        businessServiceProxy.interfaceMethod1();

        // final增强未生效
        businessServiceProxy.interfaceMethod3();
    }

    public static class LogAroundMethodInterceptor implements MethodInterceptor {

        private Object target;

        public LogAroundMethodInterceptor(Object target) {
            this.target = target;
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            // Method: intercepted Method
            // MethodProxy: used to call super
            // proxy.invokeSuper()

            String methodName = method.getName();
            System.out.println("before method 【" + methodName +"】 invoke");
            Object result;
            try {
                result = method.invoke(target, args);
            } finally {
                System.out.println("after method 【" + methodName +"】 invoke");
            }
            return result;
        }

    }

}
